package com.sj.controller;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sj.common.bean.LocalUser;
import com.sj.common.dto.comment.AdminCommentDto;
import com.sj.common.dto.comment.AdminCommentQueryParam;
import com.sj.common.dto.comment.CommentDto;
import com.sj.common.dto.comment.CommentParam;
import com.sj.common.lang.ApiResult;
import com.sj.common.lang.Const;
import com.sj.common.lang.RedisConst;
import com.sj.entity.Article;
import com.sj.entity.Comment;
import com.sj.entity.Praise;
import com.sj.entity.User;
import com.sj.interceptor.AuthCheck;
import com.sj.service.ArticleService;
import com.sj.service.CommentService;
import com.sj.service.PraiseService;
import com.sj.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 评论表 前端控制器
 * </p>
 *
 * @author 孙峻
 * @since 2022-03-09
 */
@RestController
@RequestMapping("/comment")
@Api(tags = "评论模块")
public class CommentController {

    @Autowired
    private CommentService commentService;

    @Autowired
    private UserService userService;

    @Autowired
    private ArticleService articleService;

    @Autowired
    private PraiseService praiseService;

    @AuthCheck
    @PostMapping("/admin/list")
    @ApiOperation("管理端获取评论列表")
    @Cacheable(cacheNames = "comment-list", keyGenerator = RedisConst.REDIS_SJ_KEY_GENERATOR)
    public ApiResult getAdminCommentList(@RequestBody AdminCommentQueryParam adminCommentQueryParam) {
        IPage<Comment> page = new Page<>(adminCommentQueryParam.getCurrent(), adminCommentQueryParam.getSize());
        IPage<Comment> pageInfo = commentService.getAdminCommentList(adminCommentQueryParam.getType(), page);
        IPage<AdminCommentDto> resultPage = new Page<>();
        BeanUtil.copyProperties(pageInfo, resultPage, "records");
        resultPage.setRecords(pageInfo.getRecords().stream().map(temp -> {
            AdminCommentDto adminCommentDto = new AdminCommentDto();
            BeanUtil.copyProperties(temp, adminCommentDto, "articleTitle", "user");
            adminCommentDto.setUser(userService.getUserDetailInfo(adminCommentDto.getUserId()));
            adminCommentDto.setArticleTitle(articleService.lambdaQuery().eq(Article::getId, adminCommentDto.getArticleId()).one().getTitle());
            return adminCommentDto;
        }).collect(Collectors.toList()));
        return ApiResult.success(resultPage);
    }


    @DeleteMapping("/admin/del/{id}")
    @AuthCheck
    @CacheEvict(cacheNames = {"article-num-data", "article-list", "fix-type", "comment-list", "article-detail"}, keyGenerator = RedisConst.REDIS_SJ_KEY_GENERATOR, allEntries = true)
    @ApiOperation("管理端删除评论")
    public ApiResult delFromAdmin(@PathVariable Integer id) {
        // 首先删除与该评论有关的点赞
        praiseService.remove(Wrappers.<Praise>lambdaQuery().eq(Praise::getCommentId, id));
        boolean result = commentService.remove(Wrappers.<Comment>lambdaQuery().eq(Comment::getId, id));
        if (result) {
            return ApiResult.success("删除成功");
        }
        return ApiResult.error("删除失败");
    }

    @DeleteMapping("/del/{id}")
    @AuthCheck
    @CacheEvict(cacheNames = {"article-num-data", "article-list", "fix-type", "comment-list"}, keyGenerator = RedisConst.REDIS_SJ_KEY_GENERATOR, allEntries = true)
    @ApiOperation("删除评论")
    public ApiResult delComment(@PathVariable Integer id) {
        // 首先删除与该评论有关的点赞
        praiseService.remove(Wrappers.<Praise>lambdaQuery().eq(Praise::getCommentId, id));
        boolean result = commentService.remove(Wrappers.<Comment>lambdaQuery().eq(Comment::getId, id).eq(Comment::getUserId, LocalUser.getUser().getId()));
        if (result) {
            return ApiResult.success("删除成功");
        }
        return ApiResult.error("删除失败");
    }

    /**
     * 文章id
     * 类型
     * 分页
     *
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("获取评论/回复列表")
    @Cacheable(cacheNames = "comment-list", keyGenerator = RedisConst.REDIS_SJ_KEY_GENERATOR)
    public ApiResult getCommentList(@RequestParam("articleId") Integer articleId, @RequestParam("type") String type,
                                    @RequestParam("current") Integer current, @RequestParam("size") Integer size) {
        IPage<Comment> pageInfo = new Page<>(current, size);
        IPage<Comment> tempPage = commentService.lambdaQuery().eq(Comment::getArticleId, articleId).eq(Comment::getType, type).eq(Comment::getParentId, 0)
                .orderBy(true, type.equals(Const.COMMENT), Comment::getUpdateTime, Comment::getCreateTime).page(pageInfo);
        IPage<CommentDto> resultPage = new Page<>();
        BeanUtil.copyProperties(tempPage, resultPage, "records");
        resultPage.setRecords(tempPage.getRecords().stream().map(comment -> {
            CommentDto commentDto = new CommentDto();
            BeanUtil.copyProperties(comment, commentDto, "userId", "parent", "childList", "praiseNum", "article");
            ArrayList<CommentDto> allChildList = new ArrayList<>();
            this.setCommentRelation(commentDto, allChildList);
            commentDto.setPraiseNum(this.getAnswerPraiseNum(commentDto));
            commentDto.setChildList(allChildList);
            commentDto.setUser(userService.getUserDetailInfo(comment.getUserId()));
            return commentDto;
        }).collect(Collectors.toList()));
        return ApiResult.success(resultPage);
    }

    /**
     * 获取回答问题的点赞数量
     *
     * @param commentDto
     * @return
     */
    public Long getAnswerPraiseNum(CommentDto commentDto) {
        if (commentDto.getType().equals(Const.ANSWER)) {
            return praiseService.getSumPraiseNum(commentDto.getId(), Const.ANSWER);
        }
        return 0L;
    }

    @ApiOperation("发布评论或回复")
    @PutMapping("/add")
    @AuthCheck
    @CacheEvict(cacheNames = {"comment-list", "article-detail", "article-list", "fix-type", "article-num-data"}, keyGenerator = RedisConst.REDIS_SJ_KEY_GENERATOR, allEntries = true, condition = "#result.code == 200")
    public ApiResult sendComment(@RequestBody @Validated CommentParam commentParam) {
        User user = LocalUser.getUser();
        Comment comment = new Comment();
        comment.setUserId(user.getId());
        BeanUtil.copyProperties(commentParam, comment);
        boolean result = commentService.save(comment);
        if (result) {
            return ApiResult.success("评论成功");
        }
        return ApiResult.error("评论失败");
    }

    /**
     * 获取评论的父评论 和 子评论集合
     * <p>
     * 思路：
     * 因为第一轮查的都是 parentId 为0 的评论，所有都是父评论
     * 根据自己的id 找到 parentId 为自己id的所有评论 这是自己的第一级回复
     * 递归下去 找到所有的子孙回复 存在同一个集合里面
     *
     * @param commentDto
     * @param allChildList
     */
    private void setCommentRelation(CommentDto commentDto, ArrayList<CommentDto> allChildList) {
        List<Comment> firstChildList = commentService.lambdaQuery().eq(Comment::getParentId, commentDto.getId()).orderBy(true, true, Comment::getUpdateTime, Comment::getCreateTime).list();
        List<CommentDto> childList = firstChildList.stream().map(first -> {
            CommentDto firstCommentDto = new CommentDto();
            BeanUtil.copyProperties(first, firstCommentDto, "userId", "parent", "childList", "praiseNum", "article");
            // 获取所有评论，子孙
            this.setCommentRelation(firstCommentDto, allChildList);
            // 获取父评论
            CommentDto parent = this.getCommentParent(firstCommentDto.getParentId());
            firstCommentDto.setPraiseNum(this.getAnswerPraiseNum(commentDto));
            firstCommentDto.setParent(parent);
            // 设置用户信息
            firstCommentDto.setUser(userService.getUserDetailInfo(first.getUserId()));
            return firstCommentDto;
        }).collect(Collectors.toList());
        allChildList.addAll(childList);
        Collections.reverse(allChildList);
        if (childList.size() == 0) {
            return;
        }
    }

    private CommentDto getCommentParent(Integer parentId) {
        if (parentId == 0) {
            return null;
        }
        Comment one = commentService.lambdaQuery().eq(Comment::getId, parentId).one();
        CommentDto resultDto = new CommentDto();
        BeanUtil.copyProperties(one, resultDto, "userId", "parent", "childList", "article");
        resultDto.setUser(userService.getUserDetailInfo(one.getUserId()));
        return resultDto;
    }

}
